package mornd.test3.web;

import lombok.Setter;
import lombok.ToString;
import org.springframework.boot.convert.ApplicationConversionService;
import org.springframework.format.Formatter;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.web.bind.ServletRequestParameterPropertyValues;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.support.InvocableHandlerMethod;
import org.springframework.web.servlet.mvc.method.annotation.ServletRequestDataBinderFactory;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.Date;
import java.util.Locale;

/**
 * @author: mornd
 * @dateTime: 2023/5/7 - 23:06
 * web 环境下参数与对象绑定(自定义转换)
 */
public class WebDataBinderDemo2 {
    public static void main(String[] args) throws Exception {
        User user = new User();

        MockHttpServletRequest request = new MockHttpServletRequest();
        request.setParameter("id",  "1003");
        request.setParameter("birthday",  "1998-1-1");
        request.setParameter("time",  "1998-01-02");

        // 方式一：@InitBinder 注解定义的方法内
//        InvocableHandlerMethod handlerMethod = new InvocableHandlerMethod(new MyController(), MyController.class.getMethod("aaa", WebDataBinder.class));
//        ServletRequestDataBinderFactory factory =
//                new ServletRequestDataBinderFactory(
//                        Collections.singletonList(handlerMethod), null);

        // 方式二：参数属性上添加 @DateTimeFormat 注解
        //ApplicationConversionService service =  new ApplicationConversionService();// boot 用这种实现
        DefaultFormattingConversionService service = new DefaultFormattingConversionService();
        ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
        initializer.setConversionService(service);
        ServletRequestDataBinderFactory factory =
                new ServletRequestDataBinderFactory(null, initializer);

        WebDataBinder dataBinder = factory.createBinder(new ServletWebRequest(request), user, "user");
        dataBinder.bind(new ServletRequestParameterPropertyValues(request));
        System.out.println(user);
    }

    /**
     * 自定义日期转换器
     */
    static class MyDateFormatter implements Formatter<Date> {

        @Override
        public Date parse(String text, Locale locale) throws ParseException {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            return format.parse(text);
        }

        @Override
        public String print(Date object, Locale locale) {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            return format.format(object);
        }
    }

    /**
     * 自定义日期转换器
     */
    static class MyLocalDateFormatter implements Formatter<LocalDate> {

        @Override
        public LocalDate parse(String text, Locale locale) throws ParseException {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            return LocalDate.parse(text, formatter);
        }

        @Override
        public String print(LocalDate object, Locale locale) {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            return formatter.format(object);
        }
    }

    static class MyController {

        @InitBinder
        public void myBinder(WebDataBinder webDataBinder) {
            webDataBinder.addCustomFormatter(new MyDateFormatter());
            webDataBinder.addCustomFormatter(new MyLocalDateFormatter());
        }
    }

    @Setter
    @ToString
    static class User {
        private Integer id;
        @DateTimeFormat(pattern = "yyyy-MM-dd")
        private Date birthday;
        @DateTimeFormat(pattern = "yyyy-MM-dd")
        private LocalDate time;
    }

}
